#ifndef __BLACK_MATRIX_H__
#define __BLACK_MATRIX_H__

#include "maths/default.h"
#include <xmmintrin.h>
#include "maths/valid.h"
#include "maths/vector.h"
#include "maths/quaternion.h"

namespace black
{
	// Classes :
	class mat3x3_128;
	class mat3x4_128;
	class mat4x4_128;

	// Uses :
	class vec3;
	class quat;
	class angleAxis;

	//***************************************************************
	// mat3x3_128
	//***************************************************************
	class bALIGN16 mat3x3_128
	{
	public:
		bFORCEINLINE	mat3x3_128();
		bINLINE			mat3x3_128(	float ix, float iy, float iz,
									float jx, float jy, float jz,
									float kx, float ky, float kz );
		bFORCEINLINE	mat3x3_128( const float* fVals );
		bFORCEINLINE	mat3x3_128( const vec3& vI, const vec3& vJ, const vec3& vK );
		bFORCEINLINE	mat3x3_128( const vec3_128& vI, const vec3_128& vJ, const vec3_128& vK );
		bINLINE			mat3x3_128( const quat& q );
		bINLINE			mat3x3_128( const quat_128& q );
		bINLINE			mat3x3_128( const angleAxis& aa );
		bFORCEINLINE	mat3x3_128( const mat3x3_128& m );

		// get / set
		void							setRotX		( float fAngle );
		void							setRotY		( float fAngle );
		void							setRotZ		( float fAngle );
		bFORCEINLINE void				setRot		( const quat& q );
		bFORCEINLINE void				setRot		( const quat_128& q );
		bFORCEINLINE void				setRot		( const angleAxis& aa );
		bFORCEINLINE void				setScale	( float fScale );
		bFORCEINLINE void				setScale	( float fScaleX, float fScaleY, float fScaleZ );
		bFORCEINLINE void				setScale	( const vec3& vScale );
		bFORCEINLINE void				setCol		( unsigned int i, const vec3& v );
		bFORCEINLINE void				setCol		( unsigned int i, const vec3_128& v );
		bFORCEINLINE vec3_128&			getCol		( unsigned int i );
		bFORCEINLINE const vec3_128&	getCol		( unsigned int i ) const;
		bFORCEINLINE void				setDiagonal	( float fIx, float fKy, float fKz );
		bFORCEINLINE void				setDiagonal	( const vec3& vDiag );
		bFORCEINLINE void				setRow		( unsigned int i, const vec3& v );
		bFORCEINLINE vec3				getRow		( unsigned int i ) const;
		bFORCEINLINE vec3_128&			i			();
		bFORCEINLINE const vec3_128&	i			() const;
		bFORCEINLINE vec3_128&			j			();
		bFORCEINLINE const vec3_128&	j			() const;
		bFORCEINLINE vec3_128&			k			();
		bFORCEINLINE const vec3_128&	k			() const;

		// operations
		//bFORCEINLINE mat3x3_128		operator*		( const mat3x3_128& m ) const;
		bINLINE		const mat3x3_128&	operator=		( const mat3x3_128& m );
		bINLINE		const mat3x3_128&	operator+=		( const mat3x3_128& m );
		bINLINE		const mat3x3_128&	operator-=		( const mat3x3_128& m );
		bINLINE		const mat3x3_128&	operator*=		( float fVal );
		bINLINE		const mat3x3_128&	operator/=		( float fVal );
		bINLINE		bool				operator==		( const mat3x3_128& m ) const;
		bINLINE		bool				operator!=		( const mat3x3_128& m ) const;
		bFORCEINLINE float&				operator()		( unsigned int row, unsigned int col );
		bFORCEINLINE float				operator()		( unsigned int row, unsigned int col ) const;
		bFORCEINLINE void				scale			( const vec3& vScale );
		bFORCEINLINE void				scale			( float fScale );
		bINLINE float					determinant		() const;
		bINLINE __m128					determinantsse	() const; //!< tmp
		bINLINE float					trace			() const;
		bINLINE void					setAdd			( const mat3x3_128& m1, const mat3x3_128& m2 );
		bINLINE void					setAddsse		( const mat3x3_128& m1, const mat3x3_128& m2 ); //!< tmp
		bINLINE void					setSub			( const mat3x3_128& m1, const mat3x3_128& m2 );
		void							setMul			( const mat3x3_128& m1, const mat3x3_128& m2 );
		void							setMulsse		( const mat3x3_128& m1, const mat3x3_128& m2 ); //!< tmp
		void							mul				( vec3_128& vRes, const vec3_128& vIn ) const;
		void							mulsse			( vec3_128& vRes, const vec3_128& vIn ) const; //!< tmp
		//void							mulByTranspose	( vec3_128& vRes, const vec3_128& vIn ) const;
		bINLINE void					negate			();
		bINLINE void					negatesse		(); //!< tmp
		void							transpose		();
		void							transposesse	(); //!< tmp
		void							invert			();
		void							invertsse		(); //!< tmp
		bFORCEINLINE void				invertR			();
		bFORCEINLINE void				lerp			( const mat3x3_128& m1, const mat3x3_128& m2, float fCoef );
		bFORCEINLINE mat3x3_128&		rotateX			( float fAngle );
		bFORCEINLINE mat3x3_128&		rotateY			( float fAngle );
		bFORCEINLINE mat3x3_128&		rotateZ			( float fAngle );
		//void							orthoNormalize	();

		// memory access
		bFORCEINLINE float*				ptr				();
		bFORCEINLINE const float*		ptr				() const;
		bFORCEINLINE unsigned int		size32			() const;
		bFORCEINLINE unsigned int		size8			() const;

		// misc
		bool							isValid			() const;

		static const bALIGN16 mat3x3_128 ZERO;
		static const bALIGN16 mat3x3_128 IDENTITY;

	protected:
		bALIGN16 union
		{
			bALIGN16 float m[3][4];
			bALIGN16 float f[12];
			bALIGN16 struct
			{
				float ix, iy, iz, pad0;
				float jx, jy, jz, pad1;
				float kx, ky, kz, pad2;
			} _;
			bALIGN16 struct
			{
				__m128	i;
				__m128	j;
				__m128	k;
			} _128;
			__m128 m128[3];
		};

		friend class quat;
	};

	//***************************************************************
	// mat4x4_128
	//***************************************************************
	class mat4x4_128
	{
	public:
		bFORCEINLINE	mat4x4_128();
		bINLINE			mat4x4_128(	float ix, float iy, float iz,
									float jx, float jy, float jz,
									float kx, float ky, float kz,
									float ox, float oy, float oz );
		bINLINE			mat4x4_128(	float ix, float iy, float iz, float iw,
									float jx, float jy, float jz, float jw,
									float kx, float ky, float kz, float kw,
									float ox, float oy, float oz, float ow );
		bFORCEINLINE	mat4x4_128( const float fVals[16] );
		bFORCEINLINE	mat4x4_128( const vec4& vI, const vec4& vJ, const vec4& vK, const vec4& vO );
		bFORCEINLINE	mat4x4_128( const vec4_128& vI, const vec4_128& vJ, const vec4_128& vK, const vec4_128& vO );

		// misc
		bool							isValid			() const;

	protected:
		bALIGN16 union
		{
			float m[4][4];
			float f[16];
			struct
			{
				float ix, iy, iz, iw;
				float jx, jy, jz, jw;
				float kx, ky, kz, kw;
				float ox, oy, oz, ow;
			} _;
			struct
			{
				__m128	i;
				__m128	j;
				__m128	k;
				__m128	o;
			} _128;
			__m128 m128[4];
		};

		friend class quat;
	};

	//***************************************************************
	// mat3x4_128
	//***************************************************************
	class mat3x4_128 : public mat4x4_128
	{
	public:
		bFORCEINLINE	mat3x4_128();
		bINLINE			mat3x4_128(	float ix, float iy, float iz,
									float jx, float jy, float jz,
									float kx, float ky, float kz,
									float ox, float oy, float oz );
		bFORCEINLINE	mat3x4_128( const float* fVals );
		bFORCEINLINE	mat3x4_128( const vec3& vI, const vec3& vJ, const vec3& vK, const vec3& vO );
		bFORCEINLINE	mat3x4_128( const vec3_128& vI, const vec3_128& vJ, const vec3_128& vK, const vec3_128& vO );

	protected:
		friend class quat;
	};
}

#include "maths/inl/matrix.inl"

#endif // __BLACK_MATRIX_H__
//---------------------------------------------------------------------------------------
// Copyright (c) 2009 Jounayd Id Salah.
// All rights reserved.
//---------------------------------------------------------------------------------------

